/*******************************************************************************
/
/ sred.cpp
/
/ Creado por Roberto García Carvajal.
/
/ Sistema de red. Incluye una clase de mensajes para intercambiar información. Trabaja en 2 capas.
/ Una primera capa se ocupa de interpretar los mensajes, codificarlos y decodificarlos
/ a cadenas de bytes. Esta es la capa que se ocupa de dar soporte a 64 bytes.
/ La segunda capa se ocupa de enviar y recibir los mensajes cifrados.
/
/ Hace uso de un hilo con el que se sincroniza mediante un semáforo.
/
/ Documento bajo licencia GPL.
/
*******************************************************************************/

#include <iostream>
#include <queue>
#include <cstring>
#include <fstream>
#include <SDL/SDL.h>
#include <SDL/SDL_thread.h>
#include <SDL/SDL_net.h>

#include "nucleo.h"
#include "sred.h"
#include "svideo.h"
#include "mapa.h"

// Modo debug
#define _M_R_DEBUG_ 0

// Para recibir y enviar mapas.
c_mapa mapa_remoto;

// funciones de la capa 1.
char * codificarmensaje(mensaje m);
mensaje decodificarmensaje(char * m);

char * codificarmensaje(mensaje m)
{
 char * cod;
 cod = new char[256];

 switch(m.tipo)
 {
  case M_DESCONECTAR: cod[0] = M_DESCONECTAR; break;
  case M_PUNTUACION:
  {
   cod[0] = M_PUNTUACION;
   if(sizeof(int) == 4)
    memcpy(&cod[1],&(m.cuerpo.dano),4);
   else if(sizeof(int) == 8)
   {
    char temp[8];
    memcpy(temp,&(m.cuerpo.dano),8);
    memcpy(&cod[1],&temp[4],4);
   }
  } break;
  case M_PFINAL:
  {
   cod[0] = M_PFINAL;
   if(sizeof(int) == 4)
    memcpy(&cod[1],&(m.cuerpo.dano),4);
   else if(sizeof(int) == 8)
   {
    char temp[8];
    memcpy(temp,&(m.cuerpo.dano),8);
    memcpy(&cod[1],&temp[4],4);
   }
  } break;
  case M_UNIDADS:
  {
   cod[0] = M_UNIDADS;
   if(sizeof(int) == 4)
   {
    memcpy(&cod[1],&(m.cuerpo.version[0]),4);
    memcpy(&cod[5],&(m.cuerpo.version[1]),4);
    memcpy(&cod[9],&(m.cuerpo.version[2]),4);
   }
   else if(sizeof(int) == 8)
   {
    char temp[8];
    memcpy(temp,&(m.cuerpo.version[0]),8);
    memcpy(&cod[1],&temp[4],4);
    memcpy(temp,&(m.cuerpo.version[1]),8);
    memcpy(&cod[5],&temp[4],4);
    memcpy(temp,&(m.cuerpo.version[2]),8);
    memcpy(&cod[9],&temp[4],4);
   }
  } break;
  case M_FINUNIDADS: cod[0] = M_FINUNIDADS; break;
  case M_MAPA:
  {
   // REVISAR.
   cod[0] = M_MAPA;
   memcpy(&cod[1],&(m.cuerpo.mensaje),250);
  } break;
  case M_MAPAU:
  {
   cod[0] = M_MAPAU;
   if(sizeof(int) == 4)
   {
    memcpy(&cod[1],&(m.cuerpo.version[0]),4);
    memcpy(&cod[5],&(m.cuerpo.version[1]),4);
    memcpy(&cod[9],&(m.cuerpo.version[2]),4);
   }
   else if(sizeof(int) == 8)
   {
    char temp[8];
    memcpy(temp,&(m.cuerpo.version[0]),8);
    memcpy(&cod[1],&temp[4],4);
    memcpy(temp,&(m.cuerpo.version[1]),8);
    memcpy(&cod[5],&temp[4],4);
    memcpy(temp,&(m.cuerpo.version[2]),8);
    memcpy(&cod[9],&temp[4],4);
   }
  } break;
  case M_FINMAPAU: cod[0] = M_FINMAPAU; break;
  case M_INICIA:
  {
   cod[0] = M_INICIA;
   if(sizeof(int) == 4)
    memcpy(&cod[1],&(m.cuerpo.dano),4);
   else if(sizeof(int) == 8)
   {
    char temp[8];
    memcpy(temp,&(m.cuerpo.dano),8);
    memcpy(&cod[1],&temp[4],4);
   }
  } break;
  case M_MOVIMIENTO:
  {
   cod[0] = M_MOVIMIENTO;
   if(sizeof(int) == 4)
   {
    memcpy(&cod[1],&(m.cuerpo.version[0]),4);
    memcpy(&cod[5],&(m.cuerpo.version[1]),4);
    memcpy(&cod[9],&(m.cuerpo.version[2]),4);
   }
   else if(sizeof(int) == 8)
   {
    char temp[8];
    memcpy(temp,&(m.cuerpo.version[0]),8);
    memcpy(&cod[1],&temp[4],4);
    memcpy(temp,&(m.cuerpo.version[1]),8);
    memcpy(&cod[5],&temp[4],4);
    memcpy(temp,&(m.cuerpo.version[2]),8);
    memcpy(&cod[9],&temp[4],4);
   }
  } break;
  case M_ATAQUE:
  {
   cod[0] = M_ATAQUE;
   if(sizeof(int) == 4)
   {
    memcpy(&cod[1],&(m.cuerpo.coordenadas[0]),4);
    memcpy(&cod[5],&(m.cuerpo.coordenadas[1]),4);
   }
   else if(sizeof(int) == 8)
   {
    char temp[8];
    memcpy(temp,&(m.cuerpo.coordenadas[0]),8);
    memcpy(&cod[1],&temp[4],4);
    memcpy(temp,&(m.cuerpo.coordenadas[1]),8);
    memcpy(&cod[5],&temp[4],4);
   }
  } break;
  case M_MENSAJE:
  {
   cod[0] = M_MENSAJE;
   memcpy(&cod[1],&(m.cuerpo.mensaje),250);
  } break;
  case M_EJERCITO:
  {
   cod[0] = M_EJERCITO;
   if(sizeof(int) == 4)
    memcpy(&cod[1],&(m.cuerpo.dano),4);
   else if(sizeof(int) == 8)
   {
    char temp[8];
    memcpy(temp,&(m.cuerpo.dano),8);
    memcpy(&cod[1],&temp[4],4);
   }
  } break;
  case M_C_MAPA:
  {
   cod[0] = M_C_MAPA;
   if(sizeof(int) == 4)
    memcpy(&cod[1],&(m.cuerpo.dano),4);
   else if(sizeof(int) == 8)
   {
    char temp[8];
    memcpy(temp,&(m.cuerpo.dano),8);
    memcpy(&cod[1],&temp[4],4);
   }
  } break;
  case M_MAPA_E: cod[0] = M_MAPA_E; break;
  case M_PASATURNO: cod[0] = M_PASATURNO; break;
  default: cout << "DESCONOCIDO" << endl; break;
 }
 
 return cod;
}

mensaje decodificarmensaje(char * m)
{
 mensaje men;
 char temp[8];
 temp[0] = 0;
 temp[1] = 0;
 temp[2] = 0;
 temp[3] = 0;
 
 switch(m[0])
 {
  case M_DESCONECTAR: men.tipo = M_DESCONECTAR; break;
  case M_PUNTUACION:
  {
   men.tipo = M_PUNTUACION;
   if(sizeof(int) == 4)
   {
    memcpy(&(men.cuerpo.dano),&m[1],4);
   }
   else if(sizeof(int) == 8)
   {
    memcpy(&(temp[4]),&m[1],4);
    memcpy(&(men.cuerpo.dano),temp,8);
   }
  } break;
  case M_PFINAL:
  {
   men.tipo = M_PFINAL;
   if(sizeof(int) == 4)
   {
    memcpy(&(men.cuerpo.dano),&m[1],4);
   }
   else if(sizeof(int) == 8)
   {
    memcpy(&(temp[4]),&m[1],4);
    memcpy(&(men.cuerpo.dano),temp,8);
   }
  } break;
  case M_UNIDADS:
  {
   men.tipo = M_UNIDADS;
   if(sizeof(int) == 4)
   {
    memcpy(&(men.cuerpo.version[0]),&m[1],4);
    memcpy(&(men.cuerpo.version[1]),&m[5],4);
    memcpy(&(men.cuerpo.version[2]),&m[9],4);
   }
   else if(sizeof(int) == 8)
   {
    memcpy(&(temp[4]),&m[1],4);
    memcpy(&(men.cuerpo.version[0]),temp,8);
    memcpy(&(temp[4]),&m[5],4);
    memcpy(&(men.cuerpo.version[1]),temp,8);
    memcpy(&(temp[4]),&m[9],4);
    memcpy(&(men.cuerpo.version[2]),temp,8);
   }
  } break;
  case M_FINUNIDADS: men.tipo = M_FINUNIDADS; break;
  case M_MAPA:
  { 
   // REVISAR.
   men.tipo = M_MAPA;
   memcpy(&(men.cuerpo.mensaje),&m[1],250);
  } break;
  case M_MAPAU:
  {
   men.tipo = M_MAPAU;
   if(sizeof(int) == 4)
   {
    memcpy(&(men.cuerpo.version[0]),&m[1],4);
    memcpy(&(men.cuerpo.version[1]),&m[5],4);
    memcpy(&(men.cuerpo.version[2]),&m[9],4);
   }
   else if(sizeof(int) == 8)
   {
    memcpy(&(temp[4]),&m[1],4);
    memcpy(&(men.cuerpo.version[0]),temp,8);
    memcpy(&(temp[4]),&m[5],4);
    memcpy(&(men.cuerpo.version[1]),temp,8);
    memcpy(&(temp[4]),&m[9],4);
    memcpy(&(men.cuerpo.version[2]),temp,8);
   }
  } break;
  case M_FINMAPAU: men.tipo = M_FINMAPAU; break;
  case M_INICIA:
  {
   men.tipo = M_INICIA;
   if(sizeof(int) == 4)
   {
    memcpy(&(men.cuerpo.dano),&m[1],4);
   }
   else if(sizeof(int) == 8)
   {
    memcpy(&(temp[4]),&m[1],4);
    memcpy(&(men.cuerpo.dano),temp,8);
   }
  } break;
  case M_MOVIMIENTO:
  {
   men.tipo = M_MOVIMIENTO;
   if(sizeof(int) == 4)
   {
    memcpy(&(men.cuerpo.version[0]),&m[1],4);
    memcpy(&(men.cuerpo.version[1]),&m[5],4);
    memcpy(&(men.cuerpo.version[2]),&m[9],4);
   }
   else if(sizeof(int) == 8)
   {
    memcpy(&(temp[4]),&m[1],4);
    memcpy(&(men.cuerpo.version[0]),temp,8);
    memcpy(&(temp[4]),&m[5],4);
    memcpy(&(men.cuerpo.version[1]),temp,8);
    memcpy(&(temp[4]),&m[9],4);
    memcpy(&(men.cuerpo.version[2]),temp,8);
   }
  } break;
  case M_ATAQUE:
  {
   men.tipo = M_ATAQUE;
   if(sizeof(int) == 4)
   {
    memcpy(&(men.cuerpo.coordenadas[0]),&m[1],4);
    memcpy(&(men.cuerpo.coordenadas[1]),&m[5],4);
   }
   else if(sizeof(int) == 8)
   {
    memcpy(&(temp[4]),&m[1],4);
    memcpy(&(men.cuerpo.coordenadas[0]),temp,8);
    memcpy(&(temp[4]),&m[5],4);
    memcpy(&(men.cuerpo.coordenadas[1]),temp,8);
   }
  } break;
  case M_MENSAJE:
  {
   men.tipo = M_MENSAJE;
   memcpy(&(men.cuerpo.mensaje),&m[1],250);
  } break;
  case M_EJERCITO:
  {
   men.tipo = M_EJERCITO;
   if(sizeof(int) == 4)
   {
    memcpy(&(men.cuerpo.dano),&m[1],4);
   }
   else if(sizeof(int) == 8)
   {
    memcpy(&(temp[4]),&m[1],4);
    memcpy(&(men.cuerpo.dano),temp,8);
   }
  } break;
  case M_C_MAPA:
  {
   men.tipo = M_C_MAPA;
   if(sizeof(int) == 4)
   {
    memcpy(&(men.cuerpo.dano),&m[1],4);
   }
   else if(sizeof(int) == 8)
   {
    memcpy(&(temp[4]),&m[1],4);
    memcpy(&(men.cuerpo.dano),temp,8);
   }
  } break;
  case M_PASATURNO: men.tipo = M_PASATURNO; break;
  case M_MAPA_E: men.tipo = M_MAPA_E; break;
  default: cout << "DESCONOCIDO" << endl; break;
 }
 
 return men;
}

/*******************************************************************************
/
/ Definición de los mensajes.
/
*******************************************************************************/

mensaje puntuacion(unsigned int p)
{
 mensaje m(M_PUNTUACION,p);
 return m;
}

mensaje puntuacionfinal(unsigned int p)
{
 mensaje m(M_PFINAL,p);
 return m;
}

mensaje nuevaunidad2(unsigned int unidad, unsigned int vida, unsigned int blindaje)
{
 mensaje m(M_UNIDADS,unidad,vida,blindaje);
 return m;
}

mensaje finunidades()
{
 mensaje m(M_FINUNIDADS);
 return m;
}

mensaje emapa(char * nmapa)
{
 mensaje m(M_MAPA,nmapa);
 return m;
}

mensaje colocarunidad(unsigned int unidad,unsigned int posx,unsigned int posy)
{
 mensaje m(M_MAPAU,unidad,posx,posy);
 return m;
}

mensaje fincolocarunidades()
{
 mensaje m(M_FINMAPAU);
 return m;
}

mensaje primerturno(unsigned int turno)
{
 mensaje m(M_INICIA,turno);
 return m;
}

mensaje movimiento(unsigned int unidad,unsigned int x,unsigned int y)
{
 mensaje m(M_MOVIMIENTO,unidad,x,y);
 return m;
}

mensaje ataque(unsigned int objetivo,unsigned int dano)
{
 mensaje m(M_ATAQUE,objetivo,dano);
 return m;
}

mensaje mens(char * men)
{
 mensaje m(M_MENSAJE,men);
 return m;
}

mensaje env_ejercito(int ejer)
{
 mensaje m(M_EJERCITO,ejer);
 return m;
}

mensaje pasa_turno()
{
 mensaje m(M_PASATURNO);
 return m;
}


mensaje enviar_mapa(c_mapa mapa)
{
 mensaje m(M_MAPA_E);
 mapa_remoto = mapa;
 return m;
}

mensaje tengomapa(int resp)
{
 mensaje m(M_C_MAPA,(int)resp);
 return m;
}

mensaje desconectar()
{
 mensaje m(M_DESCONECTAR);
 return m;
}

/*******************************************************************************
/
/ Definiciones de las estructuras y datos que servirán de intercambio entre el
/ proceso principal y los hilos.
/ Definiciones de las funciones que usarán los hilos.
/ Definición del semáforo.
/
*******************************************************************************/

struct sim
{
 TCPsocket rsocket, lsocket;
 IPaddress *rip;
};

sim im;

bool hiloterminado;

queue<char*> buzon_r;

int semaforo;

void wait();
void signal();

int hilo_cservidor(void * nada);
int hilo_rmensajes(void * nada);

/*******************************************************************************
/
/ Definiciones de los métodos de la clase mensaje.
/
*******************************************************************************/

mensaje::mensaje(char t)
{
 tipo = t;
}
mensaje::mensaje(char t,char * m)
{
 tipo = t;
 strcpy(cuerpo.mensaje,m);
}
mensaje::mensaje(char t,int cx, int cy)
{
 tipo = t;
 cuerpo.coordenadas[0] = cx;
 cuerpo.coordenadas[1] = cy;
}
mensaje::mensaje(char t,int v1,int v2,int v3)
{
 tipo = t;
 cuerpo.version[0] = v1;
 cuerpo.version[1] = v2;
 cuerpo.version[2] = v3;
}
mensaje::mensaje(char t,int d)
{
 tipo = t;
 cuerpo.dano = d;
}
mensaje::mensaje(char m[256])
{
 tipo = m[0];
 memcpy(&cuerpo,&m[1],256);
}
char * mensaje::convertir()
{
 char * m;
 m = new char[256];
 memcpy(&m[1],&cuerpo,256);

 return m;
}

/*******************************************************************************
/
/ Definiciones de los métodos de la clase c_sred.
/
*******************************************************************************/

void c_sred::nuevomensaje(mensaje m)
{
 char * a;
 a = codificarmensaje(m);
 
 buzon.push(a);

}

c_sred::c_sred()
{
 if(SDLNet_Init() == -1)
 {
  std::cout << "Imposible iniciar subsistema SDLNet. Error: " << SDLNet_GetError() << std::endl;
  exit(2);
 }
 vconectado=false;
 vconectando=false;
 hiloterminado=false;
 semaforo = 0;
}

c_sred::~c_sred()
{
 SDLNet_Quit();
}

void c_sred::servidor()
{
 if(SDLNet_ResolveHost(&lip,NULL,2000) == -1)
 {
  std::cout << "Imposible resolver la dirección local. Error: " << SDLNet_GetError() << std::endl;
 }
 else
 {
  if(!(im.lsocket = SDLNet_TCP_Open(&lip)))
  {
   std::cout << "Imposible abrir el socket local. Error: " << SDLNet_GetError() << std::endl;
  }
  else
  {
   hilo = SDL_CreateThread(hilo_cservidor,NULL);
   if(hilo == NULL)
    std::cout << "No se ha podido crear el hilo. Error: " << SDL_GetError() << std::endl;
   else
   {
    vconectando = true;
    std::cout << "Esperando conexion..." << std::endl;
   }
  }
 }
}

void c_sred::cliente(char * ip)
{
 rip = new IPaddress;
 if(SDLNet_ResolveHost(rip,ip,2000) == -1)
 {
  std::cout << "No se ha podido resolver la dirección ip del servidor. Error: " << SDLNet_GetError() << std::endl;
  c_sv_mensaje mens;
  mens.mensaje = G_CGUI;
  mens.parametros[0] = 0;
  svideo->nuevomensaje(mens);
 }
 else
 {
  if(!(rsocket = SDLNet_TCP_Open(rip)))
  {
   std::cout << "No se ha podido establecer conexión con el servidor. Error: " << SDLNet_GetError() << std::endl;
   c_sv_mensaje mens;
   mens.mensaje = G_CGUI;
   mens.parametros[0] = 0;
   svideo->nuevomensaje(mens);
  }
  else
  {
   mensaje m(M_CONECTAR,0,0,1);
   char * men = m.convertir();
   std::cout << sizeof(m) << std::endl;
   std::cout << m.tipo << ":" << men[0] << "@" << men[1] << "@" << men[2] << "@" << men[3] << std::endl;
   men[0] = M_CONECTAR;
   SDLNet_TCP_Send(rsocket,(void *)men,256);
   std::cout << "Se ha conectado con el servidor." << std::endl;
   vconectado=true;
   vconectando=false;
   hiloterminado=false;
   im.rsocket = rsocket;
   hilo = SDL_CreateThread(hilo_rmensajes,NULL);
   c_sv_mensaje mens;
   mens.mensaje = G_CGUI;
   mens.parametros[0] = 5;
   svideo->nuevomensaje(mens);
  }
 }
}

/*******************************************************************************
/
/ Método ciclo().
/
/ Comprueba si hay algún mensaje entrante y lo decodifica, llamándo a los
/ métodos del núcleo que corresponda.
/
/ Si hay mensajes que enviar, los envía.
/
*******************************************************************************/

void c_sred::ciclo()
{
 // Si hay mensajes listos para ser enviados los envío.
 while(!buzon.empty())
 {
  char * a = buzon.front();
  buzon.pop();
  if(_M_R_DEBUG_)
  {
   mensaje mens = decodificarmensaje(a);
   cout << "[sred]-> Enviando mensaje: ";
   switch(a[0])
   {
    case M_DESCONECTAR: cout << "M_DESCONECTAR: " << endl; break;
    case M_PUNTUACION: cout << "M_PUNTUACION: " << mens.cuerpo.dano << endl; break;
    case M_PFINAL: cout << "M_PFINAL: " << mens.cuerpo.dano << endl; break;
    case M_UNIDADS: cout << "M_UNIDADS: " << mens.cuerpo.version[0] << " " << mens.cuerpo.version[1] << " " << mens.cuerpo.version[2] << endl; break;
    case M_FINUNIDADS: cout << "M_FINUNIDADS: "<< endl; break;
    case M_MAPA: cout << "M_MAPA: " << mens.cuerpo.mensaje << endl; break;
    case M_MAPAU: cout << "M_MAPAU: " << mens.cuerpo.version[0] << " " << mens.cuerpo.version[1] << " " << mens.cuerpo.version[2] << endl; break;
    case M_FINMAPAU: cout << "M_FINMAPAU: " << endl; break;
    case M_INICIA: cout << "M_INICIA: " << mens.cuerpo.dano << endl; break;
    case M_MENSAJE:  cout << "M_MENSAJE: " << endl; break;
    case M_MOVIMIENTO:  cout << "M_MOVIMIENTO: " << mens.cuerpo.version[0] << " " << mens.cuerpo.version[1] << " " << mens.cuerpo.version[2] << endl; break;
    case M_ATAQUE:  cout << "M_ATAQUE: "<< mens.cuerpo.coordenadas[0] << " " << mens.cuerpo.coordenadas[1] << endl; break;
    case M_EJERCITO:  cout << "M_EJERCITO: " << mens.cuerpo.dano  << endl; break;
    case M_PASATURNO:  cout << "M_PASATURNO: " << endl; break;
    case M_MAPA_E: cout << "M_MAPA_E: " << endl; break;
    case M_C_MAPA: cout << "M_C_MAPA: " << mens.cuerpo.dano << endl; break;
    default: cout << "DESCONOCIDO: " << endl; break;
   }
  }
  SDLNet_TCP_Send(rsocket,a,256);
  if(a[0] == M_MAPA_E)
  {
   cout << "[sred]-> Enviando mapa." << endl;
   // Se envía el mapa.
   if(sizeof(int) == 4)
   {
    // La versión.
    if(_M_R_DEBUG_)
     cout << "[sred]-> Enviando versión." << endl;
    char mensaje1[12];
    unsigned int temp = mapa_remoto.MV();
    memcpy(mensaje1,&temp,4);
    temp = mapa_remoto.mV();
    memcpy(&(mensaje1[4]),&temp,4);
    temp = mapa_remoto.PV();
    memcpy(&(mensaje1[8]),&temp,4);
    SDLNet_TCP_Send(rsocket,mensaje1,12);
    // El ancho y el alto.
    if(_M_R_DEBUG_)
     cout << "[sred]-> Enviando ancho y alto." << endl;
    char mensaje2[8];
    temp = mapa_remoto.ancho();
    memcpy(mensaje2,&temp,4);
    temp = mapa_remoto.alto();
    memcpy(&mensaje2[4],&temp,4);
    SDLNet_TCP_Send(rsocket,mensaje2,8);
   }
   else if(sizeof(int) == 8)
   {
    // La versión.
    if(_M_R_DEBUG_)
     cout << "[sred]-> Enviando versión." << endl;
    char mensaje1[12];
    unsigned int temp = mapa_remoto.MV();
    char temp2[8];
    memcpy(temp2,&temp,8);
    memcpy(mensaje1,&temp2[4],4);
    temp = mapa_remoto.mV();
    memcpy(temp2,&temp,8);
    memcpy(&(mensaje1[4]),&temp2[4],4);
    temp = mapa_remoto.PV();
    memcpy(temp2,&temp,8);
    memcpy(&(mensaje1[8]),&temp2[4],4);
    SDLNet_TCP_Send(rsocket,mensaje1,12);
    // El ancho y el alto.
    if(_M_R_DEBUG_)
     cout << "[sred]-> Enviando ancho y alto." << endl;
    char mensaje2[8];
    temp = mapa_remoto.ancho();
    memcpy(temp2,&temp,8);
    memcpy(mensaje2,&temp2[4],4);
    temp = mapa_remoto.alto();
    memcpy(temp2,&temp,8);
    memcpy(&mensaje2[4],&temp2[4],4);
    SDLNet_TCP_Send(rsocket,mensaje2,8);
   }
   // Ahora el MD5.
   if(_M_R_DEBUG_)
    cout << "[sred]-> Enviando MD5." << endl;
   char mensaje3[33];
   memcpy(mensaje3,mapa_remoto.md5(),33);
   SDLNet_TCP_Send(rsocket,mensaje3,33);
   // Ahora el nombre del fichero del mapa.
   if(_M_R_DEBUG_)
    cout << "[sred]-> Enviando nombre del fichero." << endl;
   char mensaje4[101];
   memcpy(mensaje4,mapa_remoto.nombrefichero(),101);
   SDLNet_TCP_Send(rsocket,mensaje4,101);
   // Ahora los datos del mapa.
   if(_M_R_DEBUG_)
    cout << "[sred]-> Enviando datos." << endl;
   for(unsigned int i = 0;i < mapa_remoto.alto();i++)
   {
    SDLNet_TCP_Send(rsocket,mapa_remoto.mapa()[i],mapa_remoto.ancho());
   }
  }
  delete a;
 }
 semaforo++;
 // Si puedo acceder al buzón de entrada...
 if(semaforo > 1)
 {
  semaforo--;
 }
 else
 {// Si hay mensajes listos para leer los leo.
  while(!buzon_r.empty())
  {
   char * a = buzon_r.front();
   buzon_r.pop();
   // PROCESAR MENSAJE.
   mensaje mens = decodificarmensaje(a);
   delete a;
   if(_M_R_DEBUG_)
   {
    cout << "[sred]-> Recibido mensaje: ";
    switch(mens.tipo)
    {
    case M_DESCONECTAR: cout << "M_DESCONECTAR: " << endl; break;
    case M_PUNTUACION: cout << "M_PUNTUACION: " << mens.cuerpo.dano << endl; break;
    case M_PFINAL: cout << "M_PFINAL: " << mens.cuerpo.dano << endl; break;
    case M_UNIDADS: cout << "M_UNIDADS: " << mens.cuerpo.version[0] << " " << mens.cuerpo.version[1] << " " << mens.cuerpo.version[2] << endl; break;
    case M_FINUNIDADS: cout << "M_FINUNIDADS: "<< endl; break;
    case M_MAPA: cout << "M_MAPA: " << mens.cuerpo.mensaje << endl; break;
    case M_MAPAU: cout << "M_MAPAU: " << mens.cuerpo.version[0] << " " << mens.cuerpo.version[1] << " " << mens.cuerpo.version[2] << endl; break;
    case M_FINMAPAU: cout << "M_FINMAPAU: " << endl; break;
    case M_INICIA: cout << "M_INICIA: " << mens.cuerpo.dano << endl; break;
    case M_MENSAJE:  cout << "M_MENSAJE: " << endl; break;
    case M_MOVIMIENTO:  cout << "M_MOVIMIENTO: " << mens.cuerpo.version[0] << " " << mens.cuerpo.version[1] << " " << mens.cuerpo.version[2] << endl; break;
    case M_ATAQUE:  cout << "M_ATAQUE: "<< mens.cuerpo.coordenadas[0] << " " << mens.cuerpo.coordenadas[1] << endl; break;
    case M_EJERCITO:  cout << "M_EJERCITO: " << mens.cuerpo.dano << endl; break;
    case M_PASATURNO:  cout << "M_PASATURNO: " << endl; break;
    case M_MAPA_E: cout << "M_MAPA_E: " << endl; break;
    case M_C_MAPA: cout << "M_C_MAPA: " << mens.cuerpo.dano << endl; break;
    default: cout << "DESCONOCIDO: " << endl; break;
    }
   }
   switch(mens.tipo)
   {
    case M_DESCONECTAR: SDL_WaitThread(hilo,NULL); vconectado=false; break;
    case M_PUNTUACION: nucleo->recibe_puntuacion(mens.cuerpo.dano); break;
    case M_PFINAL: nucleo->recibe_ptos_finales(mens.cuerpo.dano); break;
    case M_UNIDADS: nucleo->recibe_remotas(mens.cuerpo.version[0],mens.cuerpo.version[1],mens.cuerpo.version[2]); break;
    case M_FINUNIDADS: nucleo->fin_unidad(); break;
    case M_MAPA: nucleo->existe_mapa(mens.cuerpo.mensaje); break;
    case M_C_MAPA: nucleo->envia_mapa_elegido(mens.cuerpo.dano); break;
    case M_MAPAU: nucleo->recibe_posicion_remotas(mens.cuerpo.version[0],mens.cuerpo.version[1],mens.cuerpo.version[2]); break;
    case M_FINMAPAU: nucleo->fin_pos_unidad(); break;
    case M_INICIA: nucleo->recibe_turno(mens.cuerpo.dano); break;
    case M_MENSAJE: svideo->mensajeremoto(mens.cuerpo.mensaje); break;
    case M_MOVIMIENTO:  nucleo->movimiento_remoto(mens.cuerpo.version[0],mens.cuerpo.version[1],mens.cuerpo.version[2]); break;
    case M_ATAQUE: nucleo->ataque_remoto(mens.cuerpo.coordenadas[0],mens.cuerpo.coordenadas[1]);  break;
    case M_EJERCITO: nucleo->recibe_ejercito_enemigo(mens.cuerpo.dano); break;
    case M_PASATURNO: nucleo->turno_pasa(); break;
    case M_MAPA_E: nucleo->fin_mapa(mapa_remoto); break;
   }
  }
  semaforo--;
 }
}

void c_sred::comprobarestadoconexion()
{
 if(hiloterminado)
 {
  int retornado;
  SDL_WaitThread(hilo,&retornado);
  if(retornado)
  {
   std::cout << "Conexión fallida." << std::endl;
   vconectado = false;
   vconectando = false;
   hiloterminado = false;
   c_sv_mensaje mens;
   mens.mensaje = G_CGUI;
   mens.parametros[0] = 0;
   svideo->nuevomensaje(mens);
  }
  else
  {
   std::cout << "Conexión exitosa." << std::endl;
   rsocket = im.rsocket;
   rip = im.rip;
   hiloterminado=false;
   vconectado=true;
   vconectando=false;
   hilo = SDL_CreateThread(hilo_rmensajes,NULL);
   c_sv_mensaje mens;
   mens.mensaje = G_CGUI;
   mens.parametros[0] = 4;
   svideo->nuevomensaje(mens);
  }
 }
}

/*******************************************************************************
/
/ Definición de las funciones de los hilos.
/
*******************************************************************************/

int hilo_cservidor(void * nada)
{
 bool continuarconexion = true;
 while(continuarconexion)
 {
  if((im.rsocket = SDLNet_TCP_Accept(im.lsocket)))
  {
   if(!(im.rip = SDLNet_TCP_GetPeerAddress(im.rsocket)))
   {
    std::cout << "No se ha podido obtener la ip del cliente. Error: " << SDLNet_GetError() << std::endl;
    hiloterminado = true;
    system("touch erroripcliente.AQUI");
    return 1;
   }
   char men[256];
   if(SDLNet_TCP_Recv(im.rsocket,men,256))
   {
    mensaje m(men);
    if((m.tipo == M_CONECTAR) && ((m.cuerpo.version[0] == 0) && (m.cuerpo.version[1] == 0) && (m.cuerpo.version[2] == 1)))
    {
     std::cout << "Versión correcta." << std::endl;
     hiloterminado = true;
     return 0;
    }
    else
    {
     system("touch errorversion.AQUI");
     fstream of("errorversion.AQUI",ios_base::out);
     of << " Tipo: " << M_CONECTAR << " RECIBIDO: " << m.tipo;
     of << " Version: " << m.cuerpo.version[0];
     of << " Subversion: " << m.cuerpo.version[1];
     of << " Parche: " << m.cuerpo.version[2];
     hiloterminado = true;
     return 1;
    }
   }
   continuarconexion=false;
  }
 }
 hiloterminado = true;
 return 0;
}

int hilo_rmensajes(void * nada)
{
 char men[256];
 bool continuar = true;
 while(continuar)
 {
  if(SDLNet_TCP_Recv(im.rsocket,men,256))
  {
   mensaje m = decodificarmensaje(men);
   if(m.tipo == M_DESCONECTAR)
    continuar = false;
   wait();
   if(m.tipo == M_MAPA_E)
   {
    char mensaje1[12];
    SDLNet_TCP_Recv(im.rsocket,mensaje1,12);
    if(sizeof(int) == 4)
    {
     // Primero la versión.
     if(_M_R_DEBUG_)
      cout << "[sred]-> Recibiendo versión." << endl;
     unsigned int temp;
     memcpy(&temp,mensaje1,4);
     mapa_remoto.MV(temp);
     memcpy(&temp,&mensaje1[4],4);
     mapa_remoto.mV(temp);
     memcpy(&temp,&mensaje1[8],4);
     mapa_remoto.PV(temp);
     // Ahora el ancho y el alto.
     if(_M_R_DEBUG_)
      cout << "[sred]-> Recibiendo ancho y alto." << endl;
     char mensaje2[8];
     SDLNet_TCP_Recv(im.rsocket,mensaje2,8);
     memcpy(&temp,mensaje2,4);
     mapa_remoto.ancho(temp);
     memcpy(&temp,&mensaje2[4],4);
     mapa_remoto.alto(temp);
    }
    else if(sizeof(int) == 8)
    {
     // Primero la versión.
     if(_M_R_DEBUG_)
      cout << "[sred]-> Recibiendo versión." << endl;
     unsigned int temp;
     char temp2[8];
     temp2[0] = 0;
     temp2[1] = 0;
     temp2[2] = 0;
     temp2[3] = 0;
     memcpy(&temp2[4],mensaje1,4);
     memcpy(&temp,&temp2,8);
     mapa_remoto.MV(temp);
     memcpy(&temp2[4],&mensaje1[4],4);
     memcpy(&temp,&temp2,8);
     mapa_remoto.mV(temp);
     memcpy(&temp2[4],&mensaje1[8],4);
     memcpy(&temp,&temp2,8);
     mapa_remoto.PV(temp);
     // Ahora el ancho y el alto.
     if(_M_R_DEBUG_)
      cout << "[sred]-> Recibiendo ancho y alto." << endl;
     char mensaje2[8];
     SDLNet_TCP_Recv(im.rsocket,mensaje2,8);
     memcpy(&temp2[4],mensaje2,4);
     memcpy(&temp,&temp2,8);
     mapa_remoto.ancho(temp);
     memcpy(&temp2[4],&mensaje2[4],4);
     memcpy(&temp,&temp2,8);
     mapa_remoto.alto(temp);
    }
    // Ahora el MD5.
    if(_M_R_DEBUG_)
     cout << "[sred]-> Recibiendo MD5." << endl;
    char mensaje3[33];
    SDLNet_TCP_Recv(im.rsocket,mensaje3,33);
    mapa_remoto.md5(mensaje3);
    // Ahora el nombre del fichero.
    if(_M_R_DEBUG_)
     cout << "[sred]-> Recibiendo nombre de fichero." << endl;
    char mensaje4[101];
    SDLNet_TCP_Recv(im.rsocket,mensaje4,101);
    mapa_remoto.nombrefichero(mensaje4);
    // Ahora los datos del mapa.
    if(_M_R_DEBUG_)
     cout << "[sred]-> Recibiendo datos." << endl;
    mapa_remoto.regenerar();
    for(unsigned int i = 0;i < mapa_remoto.alto();i++)
    {
     char * mensaje5;
     mensaje5 = new char[mapa_remoto.ancho()];
     SDLNet_TCP_Recv(im.rsocket,mensaje5,mapa_remoto.ancho());
     for(unsigned int j = 0;j < mapa_remoto.ancho();j++)
      mapa_remoto.modificar(j,i,mensaje5[j]);
    }
   }
   char * a;
   a = new char[256];
   memcpy(a,men,256);
   buzon_r.push(a);
   signal();
  }
 }
 return 0;
}

void wait()
{
 bool continuar = true;
 while(continuar)
 {
  semaforo++;
  if(semaforo > 1)
  {
   semaforo--;
   SDL_Delay(1);
  }
  else
   continuar = false;;
 }
}

void signal()
{
 semaforo--;
}
